#include "drv_gpio.h"
#include "stm32f0xx_ll_gpio.h"
#include "stm32f0xx_ll_bus.h"

/// 将 gpiox 转化为对于的gpio端口地址
#define DRV_GPIO_GPIOX_TRANS(gpiox)     ((gpiox << 10) + AHB2PERIPH_BASE)    
/// 将 pinx 转化为对于的gpio端口地址
#define DRV_GPIO_PINX_TRANS(pinx)       (1ul << pinx)

/// 端口对象实例
TDrv_Gpio_Portx g_drv_gpio_portA = {.base_addr = GPIOA,};
TDrv_Gpio_Portx g_drv_gpio_portB = {.base_addr = GPIOB,};
TDrv_Gpio_Portx g_drv_gpio_portC = {.base_addr = GPIOC,};
TDrv_Gpio_Portx g_drv_gpio_portD = {.base_addr = GPIOD,};
TDrv_Gpio_Portx g_drv_gpio_portF = {.base_addr = GPIOF,};

void Drv_Gpio_Init(void)
{
    /// 打开所有的gpio时钟
    LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);
    LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOB);
    LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOC);
    LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOD);
    LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOF);
}

void Drv_Gpio_DeInit(void)
{
    /// 关闭所有的gpio时钟
    LL_AHB1_GRP1_DisableClock(LL_AHB1_GRP1_PERIPH_GPIOF);
    LL_AHB1_GRP1_DisableClock(LL_AHB1_GRP1_PERIPH_GPIOD);
    LL_AHB1_GRP1_DisableClock(LL_AHB1_GRP1_PERIPH_GPIOC);
    LL_AHB1_GRP1_DisableClock(LL_AHB1_GRP1_PERIPH_GPIOB);
    LL_AHB1_GRP1_DisableClock(LL_AHB1_GRP1_PERIPH_GPIOA);
}

Int32 Drv_Gpio_InputSet(TDrv_Gpio_Portx* self, UInt32 pinx, UInt8 pull)
{
    Int32 result;
    if (self == NULL || pinx >= kDrv_Gpio_PinxMax || pull >= kDrv_Gpio_Pull_Max) 
        result = kDrv_Error_Param;
    else 
    {
        void* gpio = self->base_addr;
        UInt32 pin = DRV_GPIO_PINX_TRANS(pinx);
        LL_GPIO_SetPinPull((GPIO_TypeDef *)gpio, pin, pull);        ///< 设置上拉、下拉
        LL_GPIO_SetPinMode((GPIO_TypeDef *)gpio, pin, LL_GPIO_MODE_INPUT);  ///< 设置成输入模式

        result = kDrv_Error_Success;
    }

    return result;
}

Int32 Drv_Gpio_OutputSet(TDrv_Gpio_Portx* self, UInt32 pinx, UInt8 type, UInt8 pull, UInt8 speed)
{
    Int32 result;
    if (self == NULL || pinx >= kDrv_Gpio_PinxMax || type >= kDrv_Gpio_Output_Type_Max 
        || pull >= kDrv_Gpio_Pull_Max || speed >= kDrv_Gpio_Speed_Max) 
        result = kDrv_Error_Param;
    else 
    {
        void* gpio = self->base_addr;
        UInt32 pin = DRV_GPIO_PINX_TRANS(pinx);
        LL_GPIO_SetPinSpeed((GPIO_TypeDef *)gpio, pin, speed);      ///< 设置引脚输出速度
        LL_GPIO_SetPinOutputType((GPIO_TypeDef *)gpio, pin, type);                  ///< 设置开漏还是推挽
        LL_GPIO_SetPinPull((GPIO_TypeDef *)gpio, pin, pull);        ///< 设置上拉、下拉
        LL_GPIO_SetPinMode((GPIO_TypeDef *)gpio, pin, LL_GPIO_MODE_OUTPUT); ///< 设置成输出模式

        result = kDrv_Error_Success;
    }

    return result;
}


Int32 Drv_Gpio_AlternateSet(TDrv_Gpio_Portx* self, UInt32 pinx, UInt8 type, UInt8 pull, UInt8 speed, UInt8 af)
{
    Int32 result;
    if (self == NULL || pinx >= kDrv_Gpio_PinxMax || type >= kDrv_Gpio_Output_Type_Max 
        || pull >= kDrv_Gpio_Pull_Max || speed >= kDrv_Gpio_Speed_Max || af >= kDrv_Gpio_AF_Max) 
        result = kDrv_Error_Param;
    else 
    {
        void* gpio = self->base_addr;
        UInt32 pin = DRV_GPIO_PINX_TRANS(pinx);
        LL_GPIO_SetPinSpeed((GPIO_TypeDef *)gpio, pin, speed);      ///< 设置引脚输出速度
        LL_GPIO_SetPinOutputType((GPIO_TypeDef *)gpio, pin, type);  ///< 设置开漏还是推挽
        LL_GPIO_SetPinPull((GPIO_TypeDef *)gpio, pin, pull);        ///< 设置上拉、下拉
        LL_GPIO_SetPinMode((GPIO_TypeDef *)gpio, pin, LL_GPIO_MODE_ALTERNATE); ///< 设置成复用模式
        if (pinx < 8)  ///< 设置复用功能
            LL_GPIO_SetAFPin_0_7((GPIO_TypeDef *)gpio, pin, af);
        else
            LL_GPIO_SetAFPin_8_15((GPIO_TypeDef *)gpio, pin, af);
        result = kDrv_Error_Success;
    }

    return result;
}

Int32 Drv_Gpio_AnalogSet(TDrv_Gpio_Portx* self, UInt32 pinx, UInt8 pull)
{
    Int32 result;
    if (self == NULL || pinx >= kDrv_Gpio_PinxMax || pull >= kDrv_Gpio_Pull_Max) 
        result = kDrv_Error_Param;
    else
    {
        void* gpio = self->base_addr;
        UInt32 pin = DRV_GPIO_PINX_TRANS(pinx);
        LL_GPIO_SetPinPull((GPIO_TypeDef *)gpio, pin, pull);        ///< 设置上拉、下拉
        LL_GPIO_SetPinMode((GPIO_TypeDef *)gpio, pin, LL_GPIO_MODE_ANALOG); ///< 设置成模拟模式
        result = kDrv_Error_Success;
    }

    return result;
}

Int32 Drv_Gpio_WorkMode(TDrv_Gpio_Portx* self, UInt32 pinx)
{
    Int32 result;
    if (self == NULL || pinx >= kDrv_Gpio_PinxMax) 
        result = kDrv_Error_Param;
    else 
    {
        void* gpio = self->base_addr;
        UInt32 pin = DRV_GPIO_PINX_TRANS(pinx);
        result = LL_GPIO_GetPinMode((GPIO_TypeDef *)gpio, pin);    ///< 设置工作模式
    }
    return result;
}

Int32 Drv_Gpio_ReadPin(TDrv_Gpio_Portx* self, UInt32 pinx)
{
    Int32 result;
    if (self == NULL || pinx >= kDrv_Gpio_PinxMax) 
        result = kDrv_Error_Param;
    else 
    {
        void* gpio = self->base_addr;
        UInt32 pin = DRV_GPIO_PINX_TRANS(pinx);
        UInt32 mode = LL_GPIO_GetPinMode((GPIO_TypeDef *)gpio, pin);
        if (mode == LL_GPIO_MODE_INPUT)
            result = LL_GPIO_IsInputPinSet((GPIO_TypeDef *)gpio, pin);
        else if (mode == LL_GPIO_MODE_OUTPUT)
            result = LL_GPIO_IsOutputPinSet((GPIO_TypeDef *)gpio, pin);
        else
            result = kDrv_Error_WorkMode;
    }

    return result;
}

Int32 Drv_Gpio_WritePin(TDrv_Gpio_Portx* self, UInt32 pinx, Bool en)
{
    Int32 result;
    if (self == NULL || pinx >= kDrv_Gpio_PinxMax) 
        result = kDrv_Error_Param;
    else 
    {
        void* gpio = self->base_addr;
        UInt32 pin = DRV_GPIO_PINX_TRANS(pinx);
        if (LL_GPIO_GetPinMode((GPIO_TypeDef *)gpio, pin) == LL_GPIO_MODE_OUTPUT)
        {
            if (en)
                LL_GPIO_SetOutputPin((GPIO_TypeDef *)gpio, pin);
            else
                LL_GPIO_ResetOutputPin((GPIO_TypeDef *)gpio, pin);
            result = kDrv_Error_Success;
        }
        else 
            result = kDrv_Error_WorkMode;   
    }

    return result;
}
